package com.ccy.product.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ccy.product.dao.CategoryDao;
import com.ccy.product.entity.CategoryEntity;
import com.ccy.product.service.CategoryService;
import com.ccy.product.vo.Catalog2Vo;
import com.ccy.product.vo.Catalog3Vo;
import com.gulimall.common.constants.RedisKeyPrefix;
import com.gulimall.common.utils.PageUtils;
import com.gulimall.common.utils.Query;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang.StringUtils;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;


@Service("categoryService")
@Log4j2
public class CategoryServiceImpl extends ServiceImpl<CategoryDao, CategoryEntity> implements CategoryService {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private CategoryDao categoryDao;


    @Autowired
    private RedissonClient redissonClient;

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<CategoryEntity> page = this.page(
                new Query<CategoryEntity>().getPage(params),
                new QueryWrapper<CategoryEntity>()
        );

        return new PageUtils(page);
    }

    @Override
    public Map<String, List<Catalog2Vo>> getIndexCatalogs() {  // 有线程安全的问题吗？

        RLock lock = redissonClient.getLock("product:categorymanage:indexcataloglock");

        lock.lock(); //默认30s
        try{

            //1. 从redis中获取数据
            String indexcatalogs_str = stringRedisTemplate.opsForValue().get(RedisKeyPrefix.INDEX_INDEX_INDEXCATALOGS.getKeyPrefix());

            if(StringUtils.isEmpty(indexcatalogs_str)){
                //缓存没有，查询数据库
                log.info("数据库命中..................");
                log.error("");
                log.debug("");
                log.trace("");
                log.warn("");
                Map<String, List<Catalog2Vo>> map = getIndexCatalogsDb(); // 耗时操作
                stringRedisTemplate.opsForValue().set(RedisKeyPrefix.INDEX_INDEX_INDEXCATALOGS.getKeyPrefix(),JSON.toJSONString(map),RedisKeyPrefix.INDEX_INDEX_INDEXCATALOGS.getExpireTime(), TimeUnit.MINUTES);
                return map;

            }else{
                // 缓存命中，直接返回
                log.info("redis命中..................");
                return JSON.parseObject(indexcatalogs_str,new TypeReference<Map<String, List<Catalog2Vo>>>(){});
            }

        }finally {
            lock.unlock();
        }



        //1. 从redis中获取数据
//        String indexcatalogs_str = stringRedisTemplate.opsForValue().get(RedisKeyPrefix.INDEX_INDEX_INDEXCATALOGS.getKeyPrefix());
//
//        if(StringUtils.isEmpty(indexcatalogs_str)){
//            //缓存没有，查询数据库
//            log.info("数据库命中..................");
//            log.error("");
//            log.debug("");
//            log.trace("");
//            log.warn("");
//            Map<String, List<Catalog2Vo>> map = getIndexCatalogsDb(); // 耗时操作
//            stringRedisTemplate.opsForValue().set(RedisKeyPrefix.INDEX_INDEX_INDEXCATALOGS.getKeyPrefix(),JSON.toJSONString(map),RedisKeyPrefix.INDEX_INDEX_INDEXCATALOGS.getExpireTime(), TimeUnit.MINUTES);
//            return map;
//
//        }else{
//            // 缓存命中，直接返回
//            log.info("redis命中..................");
//            return JSON.parseObject(indexcatalogs_str,new TypeReference<Map<String, List<Catalog2Vo>>>(){});
//        }






    }

        public Map<String, List<Catalog2Vo>> getIndexCatalogsDb() {

        Map<String, List<Catalog2Vo>> map = new HashMap<>();
        //1. 查询所有的分类
        List<CategoryEntity> all = categoryDao.selectList(null);


        List<CategoryEntity> categorylevel1temps = getCategorysByParentId(all,0L);

        for (CategoryEntity categorylevel1temp : categorylevel1temps) {


            //2. 处理二级分类
            List<CategoryEntity> catalog2Temps = getCategorysByParentId(all,categorylevel1temp.getCatId());
            List<Catalog2Vo>  catalog2Vos = new ArrayList<>();
            ArrayList<Catalog2Vo> catalog2Vos1 = new ArrayList<>();
            for (CategoryEntity catalog2Temp : catalog2Temps) {
                Catalog2Vo catalog2Vo = new Catalog2Vo();
                catalog2Vo.setId(catalog2Temp.getCatId().toString());
                catalog2Vo.setName(catalog2Temp.getName());

                catalog2Vo.setCatalog1Id(catalog2Temp.getParentCid().toString());

                //3. 处理三级分类
                List<CategoryEntity> catalog3Temps = getCategorysByParentId(all,catalog2Temp.getCatId());
                List<Catalog3Vo>  catalog3Vos = new ArrayList<>();
                //3.1 转换  catalog3Temps --》 catalog3Vos
                for (CategoryEntity catalog3Temp : catalog3Temps) {
                    Catalog3Vo catalog3Vo = new Catalog3Vo();

                    catalog3Vo.setId(catalog3Temp.getCatId().toString());
                    catalog3Vo.setName(catalog3Temp.getName());
                    catalog3Vo.setCatalog2Id(catalog2Temp.getCatId().toString());

                    catalog3Vos.add(catalog3Vo);
                }



                catalog2Vo.setCatalog3List(catalog3Vos);

                catalog2Vos.add(catalog2Vo);



            }
            map.put(categorylevel1temp.getCatId().toString(),catalog2Vos);
        }


        return map;
    }

    private List<CategoryEntity> getCategorysByParentId(List<CategoryEntity> all,Long parentId){
        List<CategoryEntity> list = all.stream().filter(o -> {
            return o.getParentCid().equals(parentId);
        }).collect(Collectors.toList());

        return list==null?new ArrayList<>() :list;
    }

}